﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UofCASE.GreenPepe.Extensibility;
using Microsoft.VisualStudio.Modeling;
using UofCASE.GreenPepe.Runner.Events;
using Microsoft.VisualStudio.Modeling.Diagrams;
using Microsoft.VisualStudio.ComponentModelHost;
using System.Windows;
using System.ComponentModel.Composition;
using UofCASE.GreenPepe.Extensibility.Events;


namespace UofCASE.AgileProductLinerDSL {
    class GreenPepeConnector {

        private IGreenPepeService greenPepeService = null;
        private Store storeOfCurrentRun = null;
        private Diagram currentDiagram = null;
        public event EventHandler<TestExecutionCompletedEventArgs> TestExecutionCompleted;


        public GreenPepeConnector() {
            
            var componentModel = AgileProductLinerDSLPackage.GetGlobalService(typeof(SComponentModel)) as IComponentModel;
            try {
                this.greenPepeService = componentModel.GetService<IGreenPepeService>();
                this.greenPepeService.TestExecutionCompleted += new EventHandler<TestExecutionCompletedEventArgs>(OnTestExecutionCompleted);
            } catch (ImportCardinalityMismatchException) {
                ShowError();
            }
        }

        public GreenPepeConnector(IGreenPepeService greenPepeService) {
            this.greenPepeService = greenPepeService;
            this.greenPepeService.TestExecutionCompleted += new EventHandler<TestExecutionCompletedEventArgs>(OnTestExecutionCompleted);
        }

        public void OnTestExecutionCompleted(object sender, TestExecutionCompletedEventArgs args) {
            ResultHandler.SetTestResults(args.ExecutionResult.ExecutedTests, storeOfCurrentRun);
            if (this.TestExecutionCompleted != null) TestExecutionCompleted(sender, args);
        }

        public IList<TestInformation> GetAllTests(Store store) {
            if (this.greenPepeService == null) return null;
            IList<TestInformation> testInfo = this.greenPepeService.GetAllTests();

            foreach (TestInformation testInf in testInfo) {
                foreach (Test test in store.ElementDirectory.FindElements<Test>()) {
                    if (!test.IsMapped) continue;
                    if (test.RelativePath.Equals(testInf.RelativePath) && test.ProjectUniqueName.Equals(testInf.ProjectUniqueName)) {
                        testInf.IsMapped = true;
                        break;
                    }
                }
            }
            return testInfo;
        }

        /// <summary>
        /// Gets all acceptance tests from GreenPepe2010 and returns only those which are not mapped yet in the
        /// daigram which store is given as parameter.
        /// </summary>
        /// <param name="store">The store of the designated diagram.</param>
        /// <returns>List of TestInformation of unmapped tests.</returns>
        public IList<TestInformation> GetAllUnmappedTests(Store store) {
            if (this.greenPepeService == null) return null;
            IList<TestInformation> testInfo = this.greenPepeService.GetAllTests();
            IList<TestInformation> toRemove = new List<TestInformation>();
            
            foreach (TestInformation testInf in testInfo) {
                foreach (Test test in store.ElementDirectory.FindElements<Test>()) {
                    if (!test.IsMapped) continue;
                    if (test.RelativePath.Equals(testInf.RelativePath) && test.ProjectUniqueName.Equals(testInf.ProjectUniqueName)) {
                        toRemove.Add(testInf);
                        break;
                    }
                }
            }

            foreach (TestInformation testInf in toRemove) {
                testInfo.Remove(testInf);
            }
            
            return testInfo;
        }

        /// <summary>
        /// Gets all acceptance tests from GreenPepe2010 and returns only those which are mapped in the
        /// daigram which store is given as parameter.
        /// </summary>
        /// <param name="store">The store of the designated diagram.</param>
        /// <returns>List of TestInformation of mapped tests.</returns>
        public IList<TestInformation> GetAllMappedTests(Store store) {
            if (this.greenPepeService == null) return null;
            IList<TestInformation> testInfo = this.greenPepeService.GetAllTests();
            IList<TestInformation> resultList = new List<TestInformation>();
            
            foreach (TestInformation testInf in testInfo) {
                foreach (Test test in store.ElementDirectory.FindElements<Test>()) {
                    if (test.RelativePath.Equals(testInf.RelativePath) && test.ProjectUniqueName.Equals(testInf.ProjectUniqueName) && test.IsMapped) {
                        resultList.Add(testInf);
                        break;
                    }
                }
            }
            
            return resultList;
        }

        /// <summary>
        /// Runs all the tests matching to the given List of TestInformation in GreenPepe2010.
        /// </summary>
        /// <param name="testInfo"></param>
        public void ExecuteTests(IList<TestInformation> testInfo, Store store, Diagram diagram){
            // TODO Can store paramater be ommited?
            if (this.greenPepeService == null) {
                ShowError();
                return;
            }
            this.storeOfCurrentRun = store;
            this.currentDiagram = diagram;
            this.greenPepeService.RunTests(testInfo);
        }

        public bool IsGreenPepeAvailable(bool showError) {
            if (this.greenPepeService == null) {
                if (showError) ShowError();
                return false;
            } else return true;
        }

        private void ShowError() {
            MessageBox.Show(VSPackage.NoGreenPepeService, VSPackage._101,MessageBoxButton.OK,MessageBoxImage.Error);
        }
        
    }
}
